from dataclasses import dataclass
from datetime import datetime

from fastapi import status
from fastapi.exceptions import HTTPException

from app.controllers.base_controller import BaseController
from app.models.region_models import Region
from app.models.weatherforecast_models import WeatherForecast
from app.schemas.forecast_schemas import (CreateWeatherForecastRequestSchema,
                                          EditWeatherForecastRequestSchema,
                                          GetWeatherForecastResponseSchema)


@dataclass
class CreateWeatherForecastController(BaseController):
    request: CreateWeatherForecastRequestSchema

    async def execute(self) -> GetWeatherForecastResponseSchema:
        if self.request.regionId is None or self.request.regionId <= 0:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST)

        try:
            datetime.fromisoformat(str(self.request.dateTime))
        except Exception:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST)

        region = await Region.get_or_none(id=self.request.regionId)

        if region is None:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)

        new_forecast = await WeatherForecast.create(
            region=region,
            dateTime=self.request.dateTime,
            temperature=self.request.temperature,
            weatherCondition=self.request.weatherCondition,
        )

        return GetWeatherForecastResponseSchema(
            id=new_forecast.id,
            regionId=new_forecast.region_id,
            temperature=new_forecast.temperature,
            weatherCondition=new_forecast.weatherCondition,
            dateTime=new_forecast.dateTime,
        )


@dataclass
class GetWeatherForecastByIdController(BaseController):
    forecast_id: int

    async def execute(self) -> GetWeatherForecastResponseSchema:
        if self.forecast_id is None or self.forecast_id <= 0:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST)

        forecast = await WeatherForecast.get_or_none(id=self.forecast_id)

        if forecast is None:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)

        return GetWeatherForecastResponseSchema(
            id=forecast.id,
            regionId=forecast.region_id,
            temperature=forecast.temperature,
            weatherCondition=forecast.weatherCondition,
            dateTime=forecast.dateTime,
        )


@dataclass
class EditWeatherForecastController(BaseController):
    forecast_id: int
    request: EditWeatherForecastRequestSchema

    async def execute(self):
        if self.forecast_id is None or self.forecast_id <= 0:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST)

        try:
            datetime.fromisoformat(str(self.request.dateTime))
        except Exception:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST)

        forecast = await WeatherForecast.get_or_none(id=self.forecast_id)

        if forecast is None:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)

        forecast.weatherCondition = self.request.weatherCondition
        forecast.temperature = self.request.temperature
        forecast.dateTime = self.request.dateTime

        await forecast.save()

        return GetWeatherForecastResponseSchema(
            id=forecast.id,
            regionId=forecast.region_id,
            temperature=forecast.temperature,
            weatherCondition=forecast.weatherCondition,
            dateTime=forecast.dateTime,
        )


@dataclass
class DeleteWeatherForecastController(BaseController):
    forecast_id: int

    async def execute(self) -> None:
        if self.forecast_id is None or self.forecast_id <= 0:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST)

        forecast = await WeatherForecast.get_or_none(id=self.forecast_id)

        if forecast is None:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)

        await forecast.delete()
